package erfgame.core.world.terrain.file;

import java.awt.Point;
import java.io.File;


import erfgame.core.Point3D;
import erfgame.core.Point3DAndRotation;
import erfgame.core.dao.ObjectDAO;
import erfgame.core.entity.Entity;
import erfgame.core.memory.MemoryPool;
import erfgame.core.memory.Pointer;
import erfgame.core.world.World;
import erfgame.core.world.WorldDAO;
import erfgame.core.world.WorldDAOManager;
import erfgame.core.world.memory.WorldMemoryPoolFactory;
import erfgame.core.world.terrain.BlockEntityPositions;
import erfgame.core.world.terrain.BlockGridTiles;
import erfgame.core.world.terrain.BlockSurfaceImageFactory;
import erfgame.core.world.terrain.BlockSurfaceImages;

public class FileWorldDAOManager implements WorldDAOManager {
	
	private static final String TILES_EXTENSION = "path";
	private static final String SURFACES_EXTENSION = "surf";
	private static final String ENTITY_EXTENSION = "ent";

	private File baseDirectory;
	private WorldMemoryPoolFactory<byte[][][]> terrainMemoryPoolFactory;
	
	private WorldDAOManager topLevelWorldDAOManager; 
	
	public FileWorldDAOManager( File baseDirectory, WorldMemoryPoolFactory<byte[][][]> terrainMemoryPoolFactory ) {
		this.baseDirectory = baseDirectory;
		this.terrainMemoryPoolFactory = terrainMemoryPoolFactory;
	}
	
	
	public void setTopLevelWorldDAOManager(WorldDAOManager topLevelWorldDAOManager) {
		this.topLevelWorldDAOManager = topLevelWorldDAOManager;
	}

	public WorldDAO getWorldDAO() {
		return new FileWorldDAO( baseDirectory );
	}

	public ObjectDAO<Point3DAndRotation, BlockSurfaceImages> getBlockSurfaceImagesDAO( World world ) {
		File directory = this.getDirectory( world );
		int surfaceWidth = world.getBlockWidth();
		int surfaceHeight = BlockSurfaceImageFactory.getPixelY( world.getBlockHeight(), world.getBlockDepth() );
		return new FileBlockSurfaceImagesDAO( 
				directory, 
				surfaceWidth, 
				surfaceHeight 
		);
	}

	public ObjectDAO<Point3D, Pointer<byte[][][]>> getBlockTerrainDAO( World world ) {
		File directory = this.getDirectory( world );
		return new CompressingFileBlockTerrainDAO( 
				directory, 
				world.getBlockWidth(), 
				world.getBlockHeight(), 
				world.getBlockDepth(),
				terrainMemoryPoolFactory.createMemoryPool(world)
		);
	}
	
	public ObjectDAO<Point, BlockGridTiles> getGridTilesDAO(World world) {
		return new FileXYObjectDAO<BlockGridTiles>(
				new GZIPFileStreamFactory(),
//				new BaseSerializingObjectDAO<BlockGridTiles>(),
				new BlockGridTilesSerializer( world ), 
				this.getDirectory( world ), 
				TILES_EXTENSION
		);
	}

	public ObjectDAO<Point, int[][][]> getSurfacesDAO(World world) {
		return new FileXYObjectDAO<int[][][]>(
				new GZIPFileStreamFactory(),
				//new BaseSerializingObjectDAO<int[][][]>(),
				new SurfaceSerializer(world),
				this.getDirectory( world ), 
				SURFACES_EXTENSION
		);
	}
	
	public ObjectDAO<Long, Entity> getEntityDAO(World world) {
		return new EntityFileObjectDAO(
				new GZIPFileStreamFactory(),
				new BaseSerializingObjectDAO<Entity>(),
				this.getDirectory( world ), 
				ENTITY_EXTENSION, 
				world
		);
	}
	
	public ObjectDAO<Point3D, BlockEntityPositions> getBlockEntityPositionsDAO(
			World world) {
		return new FileBlockEntityPositionObjectDAO(
				getDirectory( world ), 
				new BasicFileStreamFactory(), 
				this.topLevelWorldDAOManager.getEntityDAO(world)
		);
	}


	private final File getDirectory( World world ) {
		File file = new File( this.baseDirectory, Integer.toString( world.getWorldId() ) );
		if( !file.exists() ) {
			file.mkdirs();
		}
		return file;
	}

}
